/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 * $Id: RangingTypes.hpp,v 1.11 2009-05-13 07:18:17 amaula Exp $
 *
 * \file
 * \brief MaCI - Ranging Interface Type definition header
 * \author Antti Maula <antti.maula@tkk.fi>
 */
#ifndef _MACI_RANGINGTYPES_HPP_
#define _MACI_RANGINGTYPES_HPP_
#include <inttypes.h>

namespace MaCI {

  /** MaCI - Ranging interface
   * 
   * This namespace contains all the classes and types related to the Ranging interface
   * of the MaCI - Machine Control Interface.
   *
   */
  namespace Ranging {

    /**
     * Type identifiers inside BinBag frame. Used for dynamic encoding/decoding
     * of message frames
     */
    enum ERangingType { 
      KTypeUnknown                    = -1, ///< Unknown type
      KTypeTimestamp                  = 0,  ///< Timestamp
      KTypeDistanceHeader             = 1,  ///< Distance Header
      KTypeDistance                   = 2,  ///< Distance
      KTypeDeviceInformationLimits    = 3,  ///< Device limits
      KTypeDeviceInformationPosition  = 4,  ///< Device position 
      KTypeCommand                    = 5,  ///< Device command
      KTypeReflection                 = 6
    };
    
    /**
     * Ranging command for the 'TCommand' structure. Defined in global
     * 'Ranging' namespace because otherwise l^Husers would complain :)
     */
    enum ERangingCommand { 
      KCommandUnknown             = 0,
      KCommandQueryLimits         = 1,
      KCommandQueryPosition       = 2 
    };
    
    
    /** Single distace measure.
     * 
     * Contains a single distance measure. Angles are radians,
     * distances are meters. Zero angle points to X-axis.
     */
    struct TDistance 
    {
      TDistance(const float aAngle=0, const float aDistance=0)
	: angle(aAngle),
	  distance(aDistance) {}
      float angle; ///< Angle of beam in radians
      float distance; ///< Distance of beam in meters
    };


    /** Single reflection measure.
     * 
     * Contains a single reflection measure. Angles are radians,
     * reflection are in ?. Zero angle points to X-axis.
     */
    struct TReflection
    {
      TReflection(const float aAngle=0, const float aReflection=0)
	: angle(aAngle),
	  reflection(aReflection) {}
      float angle; ///< Angle of beam in radians
      float reflection; ///< Reflection of beam in ???
    };
    
    
    /** General information about a distance measure.
     * 
     * Contains other information about the distance measuring
     * device. Also contains the number of beams in the array.
     * \todo Is the 'beam_count' field necessary? The parser
     *       is already capable of counting the beams itself.
     */
    struct TDistanceHeader 
    {
      TDistanceHeader(const float aBeamWidth=0, const unsigned int aBeamCount=0, const unsigned int aReflectionCount = 0)
	: beam_width(aBeamWidth),
	  beam_count(aBeamCount),
          reflection_count(aReflectionCount) {}
      float beam_width;           ///< Width of beam in scan (rad)
      uint32_t beam_count;    ///< Number of beams after header
      uint32_t reflection_count;    ///< Number of reflections after header
    };
  

    /** Device limits.
     *
     * This describes the ranging devices minimum and maximum
     * measuring distances. Values outside this range are to be
     * considered invalid.
     */
    struct TDeviceInformationLimits 
    {
      TDeviceInformationLimits(const float aMaxDist=0, const float aMinDist=0)
	: max_distance(aMaxDist),
	  min_distance(aMinDist) {}
      float max_distance; ///< Maximum scan distance (meters) (values over this are invalid)
      float min_distance; ///< Minimum scan distance (meters) (Values under this are invalid)
    };


    /** Device relative position.
     *
     * This structure contains information about the relative
     * position of the measuring device to some coordinate
     * system center point (like robots origo)
     *
     * \todo Do we need to add roll, pitch and yaw fields to be able
     * to fully specify a sensors position?
     *
     */
    struct TDeviceInformationPosition {
      TDeviceInformationPosition(const float aX=0, const float aY=0, 
				 const float aZ=0, const float aH=0)
	: x(aX),
	  y(aY),
	  z(aZ),
	  heading(aH) {}
      float x;            ///< Relative position X
      float y;            ///< Relative position Y 
      float z;            ///< Relative position Z
      float heading;      ///< Relative position heading
    };


    /** Ranging interface command.
     *
     * This describes the structure used for carrying
     * interface specific commands. Exact descriptions
     * of commands and their required parameters
     * are listed in the enumeration type ERangingCommand.
     *
     * \see ERangingCommand
     */
    struct TCommand {
      TCommand(ERangingCommand aCmd = KCommandUnknown) 
	: cmd(aCmd) {}
      
      uint32_t cmd;  ///< Command value.
    };
  }
}

#endif
